﻿using DefaultDspPluginsLib;
using DefaultDspPluginsLib.Depricated;
using SoundEngine3;
using SoundEngine3.AudioProcessing;
using SoundEngine3.DspPlugins;
using SoundEngine3.DspPlugins.Meta;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ZquenceStudio3.Core;
using ZquenceStudio3.Core.DspPlugins;
using ZquenceStudio3.DspPlugins;

namespace ZquenceStudio.DefaultDspPlugins.Effects
{
    public class ResonanceDescription : IDspPlugin
    {
        public DspPluginInfo GetDspPluginInfo()
        {
            return new DspPluginInfo("Resonance", DspType.Effect);
        }

        public BaseDspPluginInstance CreateDsp(ZquenceStudio3Context context, DspPluginInfo info)
        {
            return new Resonance(context, info);
        }
    }

    public class Resonance : CoreDspEffectPlugin
    {
        private IntPtr mResonancePtr;
        private Effect_Resonance mResonance = new Effect_Resonance();

        public struct ResonanceData
        {
            public int Channels;
            public int Length;
        }

#if !Portable
        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern IntPtr Effect_Resonance_Create();

        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Resonance_Delete(IntPtr ptr);

        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Resonance_SetCutoffRes(IntPtr ptr, double cutoff, double resonance);

        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Resonance_Setup(IntPtr ptr, int channels, int sampleRate);

        [DllImport(NativeSoundEngineDllImport.Dll)]
        public static extern void Effect_Resonance_Process(IntPtr reverbPtr, ref ResonanceData data,
            double[] wav_in_left, double[] wav_in_right, double[] wav_out_left, double[] wav_out_right);
#endif

        /// <summary>
        /// Get or set the flanger delta time.
        /// </summary>
        public double Cutoff
        {
            get { return mResonance.Cutoff; }
            set
            {
                mResonance.Cutoff = value;
#if !Portable
                Effect_Resonance_SetCutoffRes(mResonancePtr, mResonance.Cutoff, mResonance.Res);
#endif
            }
        }

        /// <summary>
        /// Get or set the flanger buffer length.
        /// </summary>
        public double Res
        {
            get { return mResonance.Res; }
            set
            {
                mResonance.Res = value;
#if !Portable
                Effect_Resonance_SetCutoffRes(mResonancePtr, mResonance.Cutoff, mResonance.Res);
#endif
            }
        }

        public Resonance(ZquenceStudio3Context application, DspPluginInfo info)
            : base(application, info)
        {
#if !Portable
            mResonancePtr = Effect_Resonance_Create();
#endif

            CreateParameters();

            SupportAudioProcessing = true;
        }

        ~Resonance()
        {
#if !Portable
            Effect_Resonance_Delete(mResonancePtr);
#endif
        }

        private void CreateParameters()
        {
            // Cutoff.
            ParameterPropertiesDirect cutoff = new ParameterPropertiesDirect(this);
            cutoff.Label = "Cutoff";
            cutoff.DirectGet += delegate() { return Cutoff; };
            cutoff.DirectSet += delegate(double value) { Cutoff = value; };
            cutoff.MinValue = 0.0;
            cutoff.MaxValue = 0.9;
            AddParameter(cutoff);

            // Resonante.
            ParameterPropertiesDirect resonant = new ParameterPropertiesDirect(this);
            resonant.Label = "Resonant";
            resonant.DirectGet += delegate() { return Res; };
            resonant.DirectSet += delegate(double value) { Res = value; };
            resonant.MinValue = 0;
            resonant.MaxValue = 0.93;
            AddParameter(resonant);
        }
        
        public override Version Version
        {
            get { return DspPluginInfo.DefaultVersion; }
        }

        public override string PluginInfo
        {
            get { return DspPluginInfo.DefaultPluginInfo; }
        }
        
        public override void Process(BaseAudioBuffer input, BaseAudioBuffer output)
        {
            double[] wav_in_left = input.Channels[0].Samples;     // signal
            double[] wav_in_right = input.Channels[1].Samples;     // signal
            double[] wav_out_left = output.Channels[0].Samples;     // signal
            double[] wav_out_right = output.Channels[1].Samples;     // signal

            ResonanceData data;
            data.Channels = CoreContext.SoundEngine.SoundEngineContext.OutputChannels;
            data.Length = CoreContext.SoundEngine.SoundEngineContext.BufferSize;

            if (NativeSoundEngineDllImport.UseBenchmarking)
            {
                ZquenceStudio3.Core.Utils.ProfilerMeter.Start1("Resonance");
#if !Portable
                Effect_Resonance_Process(mResonancePtr, ref data, wav_in_left, wav_in_right, wav_out_left, wav_out_right);
#endif
                ZquenceStudio3.Core.Utils.ProfilerMeter.Stop1("Resonance");
                ZquenceStudio3.Core.Utils.ProfilerMeter.Start2("Resonance");
                mResonance.Process(ref data, wav_in_left, wav_in_right, wav_out_left, wav_out_right);
                ZquenceStudio3.Core.Utils.ProfilerMeter.Stop2("Resonance");
            }
            else
            {
                if (NativeSoundEngineDllImport.UseNativeProcessing)
                {
#if !Portable
                    Effect_Resonance_Process(mResonancePtr, ref data, wav_in_left, wav_in_right, wav_out_left, wav_out_right);
#endif
                }
                else
                {
                    mResonance.Process(ref data, wav_in_left, wav_in_right, wav_out_left, wav_out_right);
                }
            }
        }

        protected override void OnChangeBufferSize(int bufferSize)
        {

        }

        protected override void OnChangeSampleRate(double sampleRate)
        {
#if !Portable
            Effect_Resonance_Setup(mResonancePtr, SoundEngineContext.OutputChannels, (int)sampleRate);
#endif
            mResonance.Setup(SoundEngineContext.OutputChannels, sampleRate);
        }

        protected override void OnChangeInputChannels(int channels)
        {

        }

        protected override void OnChangeOutputChannels(int channels)
        {
#if !Portable
            Effect_Resonance_Setup(mResonancePtr, channels, (int)SoundEngineContext.SampleRate);
#endif
            mResonance.Setup(channels, SoundEngineContext.SampleRate);
        }

        protected override void OnProcessEvents(List<SoundEngine3.MIDI.Meta.MidiMessage> midiMessages)
        {

        }
    }
}
